package org.feng.controller;

import org.feng.entity.Student;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 学习使用 webClient
 *
 * @version V1.0
 * @author: fengjinsong
 * @date: 2022年06月17日 09时03分
 */
@RequestMapping("/webclient")
@RestController
public class StudentWebClientController {
    @Resource
    private WebClient webClient;
    private final String BASE_URL = "http://localhost/student";

    @GetMapping("/{id}")
    public Mono<Student> getOneByWebClient(@PathVariable("id") Integer id) {
        return webClient.get().uri(BASE_URL + "/{id}", id).accept(MediaType.APPLICATION_JSON)
                .retrieve().bodyToMono(Student.class);
    }

    @GetMapping("/doPostSingle")
    public Mono<Student> doPostSingle() {
        Student student = new Student();
        student.setName("doPostSingle");

        return webClient.post().uri(BASE_URL + "/postSingle")
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(student)
                .retrieve()
                .bodyToMono(Student.class);
    }

    @GetMapping("/doPostForm")
    public Mono<Student> doPostForm() {
        return webClient.post().uri(BASE_URL + "/postForm?studentName={studentName}&namePrefix={namePrefix}", "小明", LocalDate.now().toString())
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .retrieve()
                .bodyToMono(Student.class);
    }

    /**
     * 请求体+路径参数
     */
    @GetMapping("/doPostRequestBody")
    public Mono<Student> doRequestBody() {
        Student student = new Student();
        student.setName("doPostRequestBody");

        int age = ThreadLocalRandom.current().nextInt(20, 30);
        return webClient.post().uri(BASE_URL + "/postRequestBody/{age}", age)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(student))
                .exchangeToMono(response -> response.bodyToMono(Student.class));
    }

    /**
     * 请求体+URL参数
     */
    @GetMapping("/doRequestBodyWithParam")
    public Mono<Student> doRequestBodyWithParam() {
        Student student = new Student();
        student.setName("doRequestBodyWithParam");
        int id = ThreadLocalRandom.current().nextInt(20, 30);
        return webClient.post().uri(BASE_URL + "/postRequestBodyWithParam?id={id}", id)
                .contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(student))
                .retrieve()
                .bodyToMono(Student.class);
    }

    @GetMapping("/doFormRequest1")
    public Mono<Student> doFormRequest() {
        Map<String, Object> paramMap = new HashMap<>(4);
        paramMap.put("id", ThreadLocalRandom.current().nextInt(20, 30));
        paramMap.put("name", "小明");

        return webClient.post().uri(BASE_URL + "/formRequest1?name={name}&id={id}", paramMap)
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .retrieve()
                .bodyToMono(Student.class);
    }

    @GetMapping("/doFormRequest2")
    public Mono<Student> testFormParam() {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("name", "value1");
        formData.add("id", "23");

        return webClient.post()
                .uri(BASE_URL + "/formRequest2")
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .body(BodyInserters.fromFormData(formData))
                .retrieve()
                .onStatus(HttpStatus::is4xxClientError, res -> Mono.error(new RuntimeException(res.statusCode() + "-自定义的")))
                .onStatus(HttpStatus::is5xxServerError, res -> Mono.error(new RuntimeException(res.statusCode() + "自定义的")))
                .bodyToMono(Student.class);
    }
}
